GtkWidget: Add ::pick vmethod
authorCarlos Garnacho <carlosg@gnome.org>
Fri, 12 May 2017 10:33:58 +0000 (12:33 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Thu, 25 May 2017 14:25:58 +0000 (16:25 +0200)
The default implementation iterates through all children, so should suffice
for most widgets.

gtk/gtkwidget.c
gtk/gtkwidget.h

index 2ed10387694b9697489fb8bbb3b1c6dde07d83bb..85628294f421e2452a67c55610941a27f1028eb0 100644 (file)
@@ -947,6 +947,78 @@ gtk_widget_real_snapshot (GtkWidget   *widget,
   /* nothing to do here */
 }
 
+static void
+transform_to_child_coords (GtkWidget *widget,
+                           GtkWidget *child,
+                           gdouble    x,
+                           gdouble    y,
+                           gdouble   *x_out,
+                           gdouble   *y_out)
+{
+  GtkAllocation alloc, child_alloc;
+  GdkWindow *window;
+  gdouble dx = 0, dy = 0;
+
+  gtk_widget_get_allocation (widget, &alloc);
+  gtk_widget_get_allocation (child, &child_alloc);
+
+  child_alloc.x -= alloc.x;
+  child_alloc.y -= alloc.y;
+
+  window = _gtk_widget_get_window (child);
+
+  while (window != _gtk_widget_get_window (widget))
+    {
+      gdk_window_coords_to_parent (window, dx, dy, &dx, &dy);
+      window = gdk_window_get_parent (window);
+    }
+
+  *x_out = x - child_alloc.x - dx;
+  *y_out = y - child_alloc.y - dy;
+}
+
+static GtkWidget *
+gtk_widget_real_pick (GtkWidget *widget,
+                      gdouble    x,
+                      gdouble    y,
+                      gdouble   *x_out,
+                      gdouble   *y_out)
+{
+  GtkAllocation allocation, parent_allocation;
+  GtkWidget *child;
+
+  gtk_widget_get_allocation (widget, &parent_allocation);
+
+  for (child = _gtk_widget_get_last_child (widget);
+       child;
+       child = _gtk_widget_get_prev_sibling (child))
+    {
+      gdouble tx = x, ty = y;
+
+      if (!gtk_widget_is_sensitive (child) ||
+          !gtk_widget_is_drawable (child))
+        continue;
+
+      transform_to_child_coords (widget, child, tx, ty, &tx, &ty);
+      _gtk_widget_get_allocation (child, &allocation);
+      allocation.x = 0;
+      allocation.y = 0;
+
+      if (gdk_rectangle_contains_point (&allocation, tx, ty))
+        {
+          if (x_out && y_out)
+            {
+              *x_out = tx;
+              *y_out = ty;
+            }
+
+          return child;
+        }
+    }
+
+  return NULL;
+}
+
 static void
 gtk_widget_class_init (GtkWidgetClass *klass)
 {
@@ -1061,6 +1133,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   klass->queue_draw_region = gtk_widget_real_queue_draw_region;
   klass->queue_draw_child = gtk_widget_real_queue_draw_child;
 
+  klass->pick = gtk_widget_real_pick;
+
   widget_props[PROP_NAME] =
       g_param_spec_string ("name",
                            P_("Widget name"),
index 60f5a7fd2a19a69d45718ffc730e6d7f270d0515..ded422a8482df955f8afe17f355e897a91759fe7 100644 (file)
@@ -480,6 +480,12 @@ struct _GtkWidgetClass
   void         (* snapshot)                    (GtkWidget            *widget,
                                                 GtkSnapshot          *snapshot);
 
+  GtkWidget *  (* pick)                        (GtkWidget *widget,
+                                                gdouble    x,
+                                                gdouble    y,
+                                                gdouble   *x_out,
+                                                gdouble   *y_out);
+
   /*< private >*/
 
   GtkWidgetClassPrivate *priv;